package com.demo.filter;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;

/**
 * 可重复读取请求体的HttpServletRequest包装器
 * 改进点：
 * - 支持大文件分块读取
 * - 自动检测字符编码
 * - 内存安全限制
 * @author gy
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private static final int MAX_BODY_SIZE = 20 * 1024 * 1024; // 10MB限制
    private final byte[] body;
    private final Charset charset;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.charset = detectCharset(request);
        this.body = readBodySafely(request.getInputStream());
    }

    /**
     * 检测请求编码
     */
    private Charset detectCharset(HttpServletRequest request) {
        String encoding = request.getCharacterEncoding();
        if (encoding == null) {
            String contentType = request.getContentType();
            if (contentType != null) {
                for (String part : contentType.split(";")) {
                    if (part.trim().startsWith("charset=")) {
                        encoding = part.split("=", 2)[1].trim();
                        break;
                    }
                }
            }
        }
        return Charset.forName(encoding != null ? encoding : "UTF-8");
    }

    /**
     * 安全读取请求体
     */
    private byte[] readBodySafely(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            int totalSize = 0;
            
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                totalSize += bytesRead;
                if (totalSize > MAX_BODY_SIZE) {
                    throw new IOException("Request body exceeds maximum allowed size");
                }
                outputStream.write(buffer, 0, bytesRead);
            }
            return outputStream.toByteArray();
        }
    }

    @Override
    public ServletInputStream getInputStream() {
        return new CachedBodyServletInputStream(new ByteArrayInputStream(body));
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(
            new ByteArrayInputStream(body), charset
        ));
    }

    /**
     * 获取请求体文本内容
     */
    public String getRequestBody() {
        return new String(body, charset);
    }

    /**
     * 线程安全的ServletInputStream实现
     */
    private static class CachedBodyServletInputStream extends ServletInputStream {
        private final ByteArrayInputStream inputStream;

        public CachedBodyServletInputStream(ByteArrayInputStream bais) {
            this.inputStream = bais;
        }

        @Override
        public int read() {
            return inputStream.read();
        }

        @Override
        public boolean isFinished() {
            return inputStream.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new UnsupportedOperationException("Not supported");
        }
    }
}
